
/**
 * @brief 实现用户态缓冲区
 * @details 使用vector<char>来存储数据,使用读写偏移量记录读和写的位置
 * 1.保存从TCP缓冲区读取的数据，防止报文不完整
 * 2.保存将要发送的数据，在TCP套接子可读的时候拷贝到TCP发送缓存区，进行数据发送
 */
#pragma once
#include <string>
#include <vector>
#include <cstring>
#include <cassert>
#include <cstdint>

#include "config.hpp"
namespace hdp
{
    class Buffer
    {
    private:
        std::vector<char> _buffer; // 使用vector进行内存空间管理
        uint64_t _reader_idx;      // 读偏移
        uint64_t _writer_idx;      // 写偏移

    public:
        Buffer() : _reader_idx(0), _writer_idx(0), _buffer(Config::GetInstance().buffer_size) {}
        ~Buffer() {}

    public:
        // 获取起始地址
        char *Begin() { return &*_buffer.begin(); }
        // 获取当前写入起始位置 _buffer的空间起始地址加上写偏移量
        char *WritePosition() { return Begin() + _writer_idx; }
        // 获取当前读物起始位置
        char *ReadPosition() { return Begin() + _reader_idx; }
        // 获取前沿空闲空间大小(缓冲区末尾)--写偏移之后的空闲空间，总体空间大小减去写偏移
        uint64_t TailIdleSize() { return _buffer.size() - _writer_idx; }
        // 获取后沿空闲空间大小(缓冲区起始)--读偏移之前的空闲空间--读偏移之前的空闲空间
        uint64_t HeadIdleSize() { return _reader_idx; }
        // 获取可读数据大小 写偏移-读偏移
        uint64_t ReadAbleSize() { return _writer_idx - _reader_idx; }

        // 将读偏移向后移动
        void MoveReadOffset(const uint64_t &len)
        {
            if (len == 0)
                return;
            // 读偏移向后移动的大小,必须小于可读数据大小
            assert(len <= ReadAbleSize());
            _reader_idx += len;
        }

        // 将写偏移向后移动
        void MoveWriteOffset(const uint64_t &len)
        {
            if (len == 0)
                return;
            // 写偏移向后移动的大小,必须小于后边的空闲空间大小
            assert(len <= TailIdleSize());
            _writer_idx += len;
        }

        // 确保可写空间足够(整体空间足够了就一定数据,否则就扩容)
        void EnsureWriteSpace(const uint64_t &len)
        {
            // 1.如果末尾空闲空间大小足够,直接返回
            if (len <= TailIdleSize())
            {
                return;
            }
            // 2.末尾空闲空间不够,则判断加上起始空闲空间大小是否足够，足够就将数据移动到起始位置
            else if (len <= TailIdleSize() + HeadIdleSize())
            {
                // 将数据移动到起始位置
                uint64_t readablesize = ReadAbleSize(); // 把当前数据大小先保存起来

                // 将数据拷贝到起始位置
                // std::copy(ReadPosition(),WritePosition(),Begin());
                std::copy(ReadPosition(), ReadPosition() + readablesize, Begin());

                _reader_idx = 0;            // 将读偏移归0
                _writer_idx = readablesize; // 将写位置置为可读数据大小
            }
            // 3.总体空间不够,则需要扩容,不移动数据,直接给写偏移之后扩容足够空间即可
            else
            {
                _buffer.resize(_writer_idx + len);
            }
        }

        // 写入数据
        void Write(const void *data, const uint64_t &len)
        {
            // 1.保证有足够的空间 2.将数据拷贝进去
            if (len == 0)
                return;
            EnsureWriteSpace(len);
            const char *d = (const char *)data;
            std::copy(d, d + len, WritePosition());
        }

        // 写入数据并且写偏移向后移动
        void WriteAndPush(const void *data, const uint64_t &len)
        {
            Write(data, len);
            MoveWriteOffset(len);
        }

        // 写入字符串
        void WriteString(std::string &data)
        {
            // return Write(&data[0], data.size());
            return Write(data.c_str(), data.size());
        }

        // 写入字符串并且写偏移向后移动
        void WriteStringAndPush(std::string &data)
        {
            WriteString(data);
            MoveWriteOffset(data.size());
        }

        // 写入一个Buffer对象
        void WriteBuffer(Buffer &data)
        {
            return Write(data.ReadPosition(), data.ReadAbleSize());
        }

        void WriteBufferAndPush(Buffer &data)
        {
            WriteBuffer(data);
            MoveWriteOffset(data.ReadAbleSize());
        }

        // 读取数据
        void Read(void *buffer, const uint64_t &len)
        {
            // 要求要获取的数据大小必须小于可读数据大小
            assert(len <= ReadAbleSize());
            std::copy(ReadPosition(), ReadPosition() + len, (char *)buffer);
        }

        // 读取数据并读偏移向后移动
        void ReadAndPop(void *buffer, const uint64_t &len)
        {
            Read(buffer, len);
            MoveReadOffset(len);
        }

        // 读取数据放入一个字符串中
        std::string ReadAsString(const uint64_t &len)
        {
            // 要求要获取的数据大小必须小于可读数据大小
            assert(len <= ReadAbleSize());
            std::string str;
            str.resize(len);
            Read(&str[0], len);
            return str;
        }

        std::string ReadAsStringAndPop(const uint64_t &len)
        {
            assert(len <= ReadAbleSize());
            std::string str = ReadAsString(len);
            MoveReadOffset(len);
            return str;
        }

        // 找到换行字符
        char *FindCRLF()
        {
            char *res = (char *)memchr(ReadPosition(), '\n', ReadAbleSize());
            return res;
        }

        // 获取一行数据
        std::string GetOneLine()
        {
            char *pos = FindCRLF();
            if (pos == nullptr)
                return "";

            // +1是为了将换行字符也取出来
            return ReadAsString(pos - ReadPosition() + 1);
        }

        std::string GetOneLineAndPop()
        {
            std::string str = GetOneLine();
            MoveReadOffset(str.size());
            return str;
        }

        // 清空缓冲区
        void Clear()
        {
            _reader_idx = 0;
            _writer_idx = 0;
        }
    };
}